import mx.utils.Delegate;

import gugga.application.ApplicatiotionNavigationalStateMemento;
import gugga.application.NavigationManager;
import gugga.application.SectionsController;
import gugga.application.SectionsTransition;
import gugga.commands.INavigationCommandReceiver;
import gugga.common.EventDescriptor;
import gugga.utils.DoLaterUtil;
import gugga.utils.Listener;

/**
 * @author Todor Kolev
 */
class gugga.application.ApplicationController 
	extends SectionsController
	implements INavigationCommandReceiver
{
	private var mPendingSectionPath : String;
	private var mTargetSectionPath : String;
	private var mFullTransition : SectionsTransition;
	
	public function get TargetSectionPath() : String
	{
		return mTargetSectionPath;
	}
	
	function ApplicationController()
	{
		super();
		_global.ApplicationController = this;
	}

	private function initUI() : Void
	{
		super.initUI();
		show();
	}
	
	/*
	 * This is the implementation of the "INavigationCommandReceiver" method.
	 * Here, all necessary information required to restore full application state if command is reversed,
	 * is persisted into a memento (state data). (See Memento Design Pattern)
	 */  
	public function createNavigationState() : ApplicatiotionNavigationalStateMemento 
	{
		var state = new ApplicatiotionNavigationalStateMemento();
		state.NavigationPath = mCurrentSectionPath;
		
		return state;
	}
	
	/* 
	 * This is the implementation of the "INavigationCommandReceiver" method.
	 */
	public function setNavigationState(aMemento : ApplicatiotionNavigationalStateMemento) : Void
	{
		navigateTo(aMemento.NavigationPath);
	}
	
	/* 
	 * This is the implementation of the "INavigationCommandReceiver" method,
	 * which substitutes the method "onNavigateTo" used by section and application containers 
	 * for default navigation without commands.
	 */  
	public function navigateTo(aSectionPath:String) : Boolean
	{
		var result : Boolean = false;
		
		if(aSectionPath == mCurrentSectionPath)
		{
			result = false;
		}
		else
		{	
			if(mFullTransition && mFullTransition.isRunning())
			{ 
				if(aSectionPath == mTargetSectionPath || aSectionPath == mPendingSectionPath)
				{
					result = false;
				}
				else
				{
					result = true;
				}
			
				var hasPendingSectionPath : Boolean = false;
				if(mPendingSectionPath)
				{
					hasPendingSectionPath = true;
				}
				
				mPendingSectionPath = aSectionPath;
				
				//there was no mPendingSectionPath, so the interruption is still not started
				//TODO: What if the mFullTransition.canInterrupt() returns false, and interruption is not 
				//started. More efficiant check should be performed.
				if(!hasPendingSectionPath)
				{
					if(canInterruptCurrentTransition())
					{
						interruptCurrentTransition();
					}
				}
			}
			else if(!mFullTransition)
			{
				var transition : SectionsTransition = openSection(aSectionPath);
				mFullTransition = transition;
				
				if(mFullTransition)
				{
					//TODO: should set mTargetSectionPath to null when sections are swapped
					mTargetSectionPath = aSectionPath;
					
					Listener.createSingleTimeListener(
						new EventDescriptor(mFullTransition, "disposed"), 
						Delegate.create(this, onTransitionDisposed2)
					);
					
					NavigationManager.Instance.markNavigations(aSectionPath);
					result =  true;
				}
				else
				{
					result = false;
				}
			}
		}
		
		return result;		
	}	
	
	private function canInterruptCurrentTransition() : Boolean
	{
		return mFullTransition.canInterrupt() && !isSectionClosing(mPendingSectionPath);
	}	
		
	private function interruptCurrentTransition() : Void
	{
		Listener.createSingleTimeListener(
			new EventDescriptor(mFullTransition, "interrupted"), 
			Delegate.create(this, onFullTransitionInterrupted)
		);
		
		mFullTransition.interrupt();
	}
		
	private function onFullTransitionInterrupted(ev) : Void 
	{
		NavigationManager.Instance.markNavigations(mCurrentSectionPath);
	}
		
	private function onTransitionDisposed2(ev) : Void 
	{
		//wait for a while to ensure everyone is finished his job for this interruption
		DoLaterUtil.doLater(this, onTransitionDisposed2Actual, [ev], 1);
	}
	
	private function onTransitionDisposed2Actual(ev) : Void 
	{
		delete mFullTransition;
		
		if(mPendingSectionPath)
		{
			var pendingSectionPath : String = mPendingSectionPath;
			mPendingSectionPath = null;
			
			navigateTo(pendingSectionPath);
		}
	}
		
	/*
	private function harvestFullCurrentSectionPath() : String
	{
		var sectionPath : String = "";
		var sectionsController : SectionsController = this;
		
		while(sectionsController && sectionsController.CurrentSectionID)
		{
			if(sectionPath != "")
			{
				sectionPath += ".";
			}
			
			sectionPath += sectionsController.CurrentSectionID;
			
			sectionsController = SectionsController(sectionsController.CurrentSection);
		}
		
		return sectionPath;
	}
	 */
}